#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/vfs.h>
#include <sys/stat.h>

#define BLOCKSIZ	1024

#define NDZONES		7
#define NINDIRS		(BLOCKSIZ / sizeof(int))

int calc_blocks(int length)
{
	int count = 0;
	int tmp;

	if (length <= (NDZONES * BLOCKSIZ))
	{
		tmp = length % BLOCKSIZ;
		count = length / BLOCKSIZ;
		
		if (tmp)
		{
			count++;
		}

		return count;
	}

	length -= NDZONES * BLOCKSIZ;
	count = NDZONES;
	count++;

	if (length <= (NINDIRS * BLOCKSIZ))
	{
		count += length / BLOCKSIZ;
		tmp = length % BLOCKSIZ;

		if (tmp)
		{
			count++;
		}

		return count;
	}

	length -= NINDIRS * BLOCKSIZ;
	count += NINDIRS;
	count++;

	if (length > (NINDIRS * NINDIRS * BLOCKSIZ))
	{
		return -1;
	}

	count += length / (NINDIRS * BLOCKSIZ);
	if (length % (NINDIRS * BLOCKSIZ))
	{
		count++;
	}

	count += length / BLOCKSIZ;
	if (length % BLOCKSIZ)
	{
		count++;
	}

	
	return count;
}

int get_fs_free_blocks(void)
{
	struct statfs fs;

	if (statfs(".", &fs) < 0)
	{
		return -1;
	}

	return fs.f_bavail;
}

int get_file_block(const char *pathname)
{
	struct stat st;

	if (stat(pathname, &st) < 0)
	{
		printf("stat file failed: %s\n", strerror(errno));

		return -1;
	}

	return st.st_size;
}

int main(int argc, char *argv[])
{
	int new_size;
	int old_size;
	int fs_prev_count;
	int fs_next_count;
	int file_prev_count;
	int file_next_count;


	if (argc != 3)
	{
		printf("usage: %s filename newsize \n", argv[0]);

		return 1;
	}

	new_size = atoi(argv[2]);
	old_size = get_file_block(argv[1]);

	file_prev_count = calc_blocks(old_size);
	file_next_count = calc_blocks(new_size);

	fs_prev_count = get_fs_free_blocks();

	if (truncate(argv[1], new_size) < 0)
	{
		printf("truncate error: %s\n", strerror(errno));
		return 1;
	}

	fs_next_count = get_fs_free_blocks();

	if ((fs_prev_count - fs_next_count) ==
		(file_next_count - file_prev_count))
	{
		printf("test OK!\n");
	}
	else
	{
		printf("=========================\n");
		printf("test FAILED!\n");
		printf("oldsize %d occupied %d blocks!\n", old_size,
					calc_blocks(old_size));
		printf("newsize%d occupied %d blocks!\n", new_size,
					calc_blocks(new_size));
		printf("fs old free %d blocks!\n", fs_prev_count);
		printf("fs new free %d blocks!\n", fs_next_count);
	}

	return 0;
}


